using System;
using System.Collections.Generic;
using System.Text;

using System.Web;
using Deepcode.Flux.Core.Systems.CMS;
using Deepcode.Flux.Core.Systems.CMS.Mappings;

namespace Deepcode.Flux.Core.Systems.URLRewriter
{
	public class Rewriter
	{
		/// <summary>
		/// Implements re-writing for the main default.aspx page. Use this 
		/// </summary>
		/// <param name="context"></param>
		public void RewriteFromHome(HttpContext context)
		{
			string DomainName = context.Request.ServerVariables["SERVER_NAME"];
			DomainMappings dm = new DomainMappings();
		    DomainMapping m = dm.GetByDomain( DomainName );
			if( m == null ) return;

			ContentObject node = m.Homepage_Current;
			if( node == null ) return;
			if( node.TypeTemplate == null ) throw new Exception(String.Format("Could not load {0} type", node.FK_STypeID));

			string template = node.TypeTemplate.Fields["Template"];
			if( template == "" ) throw new Exception(String.Format("Type {0} does not have a Template key", node.FK_STypeID));
			string qs = "&" + context.Request.QueryString.ToString();
			qs += "&nodeid=" + node.PK_ID.ToString();
			if (!template.Contains("?")) template += "?";
			template += qs;

			context.Server.Transfer( template, false );
		}
		/// <summary>
		/// Implements the actual re-writing engine for the URL Rewriter Module
		/// </summary>
		/// <param name="app"></param>
		public void DoRewriting(HttpApplication app)
		{
			// Extract the various portions of the request URL
			string DomainName = app.Request.ServerVariables["SERVER_NAME"];
			string VirtualApplicationPath = app.Request.ApplicationPath;
			string MappingPath = app.Request.Path;
			string MappingPathNoExtension = MappingPath;
			string QueryString = app.Request.ServerVariables["QUERY_STRING"];

			if( (VirtualApplicationPath != "/") && MappingPath.StartsWith( VirtualApplicationPath, true, null )) 
				MappingPath = MappingPath.Substring( VirtualApplicationPath.Length );

			// See if a physical file exists - if so use that
			string PhysicalFile = app.Server.MapPath(app.Request.Path);
			if (System.IO.File.Exists(PhysicalFile)) return;
			
			// If physical file doesn't end .aspx, we're not interested
			if( ! PhysicalFile.EndsWith(".aspx") ) return;
			MappingPathNoExtension = MappingPath.Substring(0, MappingPath.Length - 5);
			
			// Look up the domain
			DomainMappings mappings = new DomainMappings();
			DomainMapping map = mappings.GetByDomain( DomainName );
			if( map == null ) return;

			// Create a content manager
			ContentManager m = new ContentManager();
			// Find path from the domain root, if domain root is valid
			ContentObject root = map.Rootpage_Current;
			if( root != null )
			{
				ContentObject node = m.AdxGetByPath( root.PK_ID, MappingPathNoExtension );
				if (node != null)
				{
					if( node.TypeTemplate == null ) throw new Exception(String.Format("Could not load {0} type", node.FK_STypeID));
					string template = node.TypeTemplate.Fields["Template"];
					if( template == "" ) throw new Exception(String.Format("Type {0} does not have a Template key", node.FK_STypeID));
					string qs = "&" + QueryString;
					qs += "&nodeid=" + node.PK_ID.ToString();
					if (!template.Contains("?")) template += "?";
					template += qs;

					app.Context.RewritePath(ResolveUrl(app.Request.ApplicationPath, template), false);
				}
			}

			// Find path from absolute root
			ContentObject node2 = m.AdxGetByPath( -1, MappingPathNoExtension );
			if (node2 != null)
			{
				if( node2.TypeTemplate == null ) throw new Exception(String.Format("Could not load {0} type", node2.FK_STypeID));
				string template = node2.TypeTemplate.Fields["Template"];
				if( template == "" ) throw new Exception(String.Format("Type {0} does not have a Template key", node2.FK_STypeID));
				string qs = "&" + QueryString;
				qs += "&nodeid=" + node2.PK_ID.ToString();
				if (!template.Contains("?")) template += "?";
				template += qs;

				app.Context.RewritePath(ResolveUrl(app.Request.ApplicationPath, template), false);
			}

			// See if we have a path that is of a numeric ID
			int lastIndex = MappingPathNoExtension.LastIndexOf("/");
			if (lastIndex > -1)
			{
				string numString = MappingPathNoExtension.Substring( lastIndex +1 );
				int i = -1;
				try { i = Int32.Parse(numString); }
				catch { }

				if (i != -1)
				{
					ContentObject node = m.AdxGetByID( i );
					if (node != null)
					{
						if (node.TypeTemplate == null) throw new Exception(String.Format("Could not load {0} type", node.FK_STypeID));
						string template = node.TypeTemplate.Fields["Template"];
						if (template == "") throw new Exception(String.Format("Type {0} does not have a Template key", node.FK_STypeID));
						string qs = "&" + QueryString;
						qs += "&nodeid=" + node.PK_ID.ToString();
						if (!template.Contains("?")) template += "?";
						template += qs;

						app.Context.RewritePath(ResolveUrl(app.Request.ApplicationPath, template), false);
					}
				}
			}
			/*
			app.Context.Response.Clear();
			app.Context.Response.Write(String.Format("Physi: {0}<br/>", PhysicalFile));
			app.Context.Response.Write(String.Format("Domai: {0}<br/>", DomainName));
			app.Context.Response.Write(String.Format("VApp : {0}<br/>", VirtualApplicationPath));
			app.Context.Response.Write(String.Format("Map  : {0}<br/>", MappingPath));
			app.Context.Response.Write(String.Format("MapNP: {0}<br/>", MappingPathNoExtension));
			app.Context.Response.Write(String.Format("Query: {0}<br/>", QueryString));
			app.Context.Response.End();
			 */

		}
		/// <summary>
		/// Internal replacement for resolve Url
		/// </summary>
		/// <param name="appPath"></param>
		/// <param name="url"></param>
		/// <returns></returns>
		internal static string ResolveUrl(string appPath, string url)
		{
			if (url.Length == 0 || url[0] != '~')
				return url;		// there is no ~ in the first character position, just return the url
			else
			{
				if (url.Length == 1)
					return appPath;  // there is just the ~ in the URL, return the appPath
				if (url[1] == '/' || url[1] == '\\')
				{
					// url looks like ~/ or ~\
					if (appPath.Length > 1)
						return appPath + "/" + url.Substring(2);
					else
						return "/" + url.Substring(2);
				}
				else
				{
					// url looks like ~something
					if (appPath.Length > 1)
						return appPath + "/" + url.Substring(1);
					else
						return appPath + url.Substring(1);
				}
			}
		}
	}
}
